This R script is used to merge RS data downloaded the Google Drive folder shared by Bea with the ReSurvey database.

Load libraries

library(tidyverse)
library(here)

Read files with RS data from Bea

S2

NDVI & NDMI

NOTE: To be updated with files in folders “New_filter”

# Set the folder path
folder_path <- "C:/Data/MOTIVATE/MOTIVATE_RS_data/S2"

# List only CSV files that contain "max_Filtered" in their filename
csv_files <- list.files(folder_path, pattern = "max_Filtered.*\\.csv$",
                        full.names = TRUE, recursive = TRUE)

# Function to read each file and extract info from the filename
read_and_label <- function(file_path) {
  file_name <- basename(file_path)
  
  # Extract region and subregion from the filename
  # Updated regular expression to handle the case where subregion is missing
  components <- str_match(file_name,
                          "^[0-9_]*([^_]+)_([^_]+)_Sentinel.*?_(.*?).csv")
  
  # Extract the biogeo and unit, handling missing subregion (unit)
  biogeo <- components[2]
  
  # If subregion (unit) is missing, set it as NA
  unit <- ifelse(is.na(components[3]), NA, components[3])
  
  # Check if biogeo is missing, and if so,
  # assign the first part of the filename (region name)
  if (is.na(biogeo) && grepl("Sentinel", file_name)) {
    # Capture the first part (biogeo) directly
    biogeo <- str_match(file_name, "^[0-9_]*([^_]+)_Sentinel")[2]
  }
  
  # If biogeo is still NA, print a warning
  if (is.na(biogeo)) {
    warning(paste("Failed to extract biogeo for file:", file_name))
  }

  # Read CSV and add columns for extracted info
  read_csv(file_path) %>%
    mutate(biogeo = biogeo, unit = unit)
}
# Read and merge all CSV files
data_RS_S2 <- map_dfr(csv_files, read_and_label)
Rows: 2442 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 268 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 64 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 689 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 3919 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2639 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 3206 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 3187 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 3854 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2440 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 388 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2784 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 1 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 339 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 980 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2948 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 175 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 1070 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2345 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 247 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2684 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 4293 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 4591 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 4479 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 4636 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 4318 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 4612 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2569 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 358 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 762 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 15 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 31 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 2979 Columns: 10── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): system:index, source, .geo
dbl (7): Lat_update, Lon_update, NDMI, NDVI, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# View the resulting tibble
print(data_RS_S2)

# Counts per biogeo and unit
print(data_RS_S2 %>% count(biogeo, unit), n = 100)

Data cleaning S2 NDVI & NDMI

data_RS_S2 <- data_RS_S2 %>%
  # Keep the columns we need
  select(obs_unique, biogeo, unit, year, source, Lat_update, Lon_update,
         NDVI, NDMI) %>%
  # Rename Lat and Lon, these are only kept in case there is difference with
  # those in the ReSurvey database due to updates based on Ilona's info
  rename(Lat_RS = Lat_update, Lon_RS = Lon_update) %>%
  # Same for year
  rename(year_RS = year)

SOS, Peak and EOS

# Set the folder path
folder_path <- "C:/Data/MOTIVATE/MOTIVATE_RS_data/S2"

# List only CSV files that contain "NDVI_Phenology" in their filename
csv_files <- list.files(folder_path, pattern = "NDVI_Phenology.*\\.csv$",
                        full.names = TRUE, recursive = TRUE)

# Function to read each file and extract info from the filename
read_and_label <- function(file_path) {
  file_name <- basename(file_path)
  
  # Extract region and subregion from the filename
  # Updated regular expression to handle the case where subregion is missing
  components <- str_match(file_name,
                          "^[0-9_]*([^_]+)_([^_]+)_NDVI_Phenology.*?_(.*?).csv")
  
  # Extract the biogeo and unit, handling missing subregion (unit)
  biogeo <- components[2]
  
  # If subregion (unit) is missing, set it as NA
  unit <- ifelse(is.na(components[3]), NA, components[3])
  
  # Check if biogeo is missing, and if so,
  # assign the first part of the filename (region name)
  if (is.na(biogeo) && grepl("_NDVI_Phenology", file_name)) {
    # Capture the first part (biogeo) directly
    biogeo <- str_match(file_name, "^[0-9_]*([^_]+)_NDVI_Phenology")[2]
  }
  
  # If biogeo is still NA, print a warning
  if (is.na(biogeo)) {
    warning(paste("Failed to extract biogeo for file:", file_name))
  }

  # Read CSV and add columns for extracted info
  read_csv(file_path) %>%
    mutate(biogeo = biogeo, unit = unit)
}
# Read and merge all CSV files
data_RS_S2_phen <- map_dfr(csv_files, read_and_label)
Rows: 2442 Columns: 14── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): system:index, .geo
dbl  (9): EOS_DOY, Lat_update, Lon_update, Peak_DOY, SOS_DOY, obs_unique, plot_uniqu, t1, year
date (3): EOS_Date, Peak_Date, SOS_Date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 268 Columns: 14── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): system:index, .geo
dbl  (9): EOS_DOY, Lat_update, Lon_update, Peak_DOY, SOS_DOY, obs_unique, plot_uniqu, t1, year
date (3): EOS_Date, Peak_Date, SOS_Date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 689 Columns: 14── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): system:index, .geo
dbl  (9): EOS_DOY, Lat_update, Lon_update, Peak_DOY, SOS_DOY, obs_unique, plot_uniqu, t1, year
date (3): EOS_Date, Peak_Date, SOS_Date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 980 Columns: 14── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): system:index, .geo
dbl  (9): EOS_DOY, Lat_update, Lon_update, Peak_DOY, SOS_DOY, obs_unique, plot_uniqu, t1, year
date (3): EOS_Date, Peak_Date, SOS_Date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 1 Columns: 14── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): system:index, .geo
dbl  (9): EOS_DOY, Lat_update, Lon_update, Peak_DOY, SOS_DOY, obs_unique, plot_uniqu, t1, year
date (3): EOS_Date, Peak_Date, SOS_Date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 339 Columns: 14── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): system:index, .geo
dbl  (9): EOS_DOY, Lat_update, Lon_update, Peak_DOY, SOS_DOY, obs_unique, plot_uniqu, t1, year
date (3): EOS_Date, Peak_Date, SOS_Date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# View the resulting tibble
print(data_RS_S2_phen)

# Counts per biogeo and unit
print(data_RS_S2_phen %>% count(biogeo, unit), n = 100)

Data cleaning S2 SOS, Peak and EOS

data_RS_S2_phen <- data_RS_S2_phen %>%
  # Keep the columns we need
  select(obs_unique, biogeo, unit, SOS_DOY, SOS_Date, Peak_DOY, Peak_Date,
         EOS_DOY, EOS_Date)
  # Remove Lat and Lon and year, in case there is difference with
  # those in the ReSurvey database due to updates based on Ilona's info,
  # we have Lat_RS, Lon_RS and year_RS from data_RS_S2

Landsat

NDVI, NDMI & other stuff

NOTE: some regions missing (at least CON)

# Set the folder path
folder_path <- "C:/Data/MOTIVATE/MOTIVATE_RS_data/Landsat"

# List only CSV files that contain "Plot" in their filename
csv_files <- list.files(folder_path, pattern = "Plot.*\\.csv$",
                        full.names = TRUE, recursive = TRUE)

# Remove ALP_BAL so far cause there seems to be an error in that table

csv_files <- csv_files[-1] 

# Define the expected column names
expected_columns <- c("system:index", "Lat_update", "Lon_update", "obs_unique",
                      "plot_uniqu", "source",   "year", "EVI_max",  "EVI_median",
                      "EVI_min", "EVI_p10", "EVI_p90",  "EVI_stdDev",   "EVImean",
                      "NDMI_max",   "NDMI_median",  "NDMI_min", "NDMI_p10",
                      "NDMI_p90",   "NDMI_stdDev",  "NDMImean", "NDVI_max",
                      "NDVI_median",    "NDVI_min", "NDVI_p10", "NDVI_p90",
                      "NDVI_stdDev",    "NDVImean", "NDWI_max", "NDWI_median",
                      "NDWI_min",   "NDWI_p10", "NDWI_p90", "NDWI_stdDev",
                      "NDWImean",   "SAVI_max", "SAVI_median",  "SAVI_min",
                      "SAVI_p10",   "SAVI_p90", "SAVI_stdDev",  "SAVImean", ".geo") 

# Define the column types
column_types <- cols(
  `system:index` = col_character(), Lat_update = col_double(),
  Lon_update = col_double(), obs_unique = col_double(),
  plot_uniqu = col_character(), source = col_character(), year = col_integer(),
  EVI_max = col_double(), EVI_median = col_double(), EVI_min = col_double(),
  EVI_p10 = col_double(), EVI_p90 = col_double(), EVI_stdDev = col_double(),
  EVImean = col_double(), NDMI_max = col_double(), NDMI_median = col_double(),
  NDMI_min = col_double(), NDMI_p10 = col_double(), NDMI_p90 = col_double(),
  NDMI_stdDev = col_double(), NDMImean = col_double(), NDVI_max = col_double(),
  NDVI_median = col_double(), NDVI_min = col_double(), NDVI_p10 = col_double(),
  NDVI_p90 = col_double(), NDVI_stdDev = col_double(), NDVImean = col_double(),
  NDWI_max = col_double(), NDWI_median = col_double(), NDWI_min = col_double(),
  NDWI_p10 = col_double(), NDWI_p90 = col_double(), NDWI_stdDev = col_double(),
  NDWImean = col_double(), SAVI_max = col_double(), SAVI_median = col_double(),
  SAVI_min = col_double(), SAVI_p10 = col_double(), SAVI_p90 = col_double(),
  SAVI_stdDev = col_double(), SAVImean = col_double(), .geo = col_character()
)

# Function to read each file and extract info from the filename
read_and_label <- function(file_path) {
  file_name <- basename(file_path)
  
  # Extract region and subregion from the filename
  # Updated regular expression to handle the case where subregion is missing
  components <- str_match(file_name,
                          "^[0-9_]*([^_]+)_([^_]+)_Landsat.*?_(.*?).csv")
  
  # Extract the biogeo and unit, handling missing subregion (unit)
  biogeo <- components[2]
  
  # If subregion (unit) is missing, set it as NA
  unit <- ifelse(is.na(components[3]), NA, components[3])
  
  # Check if biogeo is missing, and if so,
  # assign the first part of the filename (region name)
  if (is.na(biogeo) && grepl("Landsat", file_name)) {
    # Capture the first part (biogeo) directly
    biogeo <- str_match(file_name, "^[0-9_]*([^_]+)_Landsat")[2]
  }
  
  # If biogeo is still NA, print a warning
  if (is.na(biogeo)) {
    warning(paste("Failed to extract biogeo for file:", file_name))
  }
  
  delimiter <- ifelse(grepl(";", readLines(file_path, n = 1)), ";", ",")
  
  # Read CSV and add columns for extracted info
  data <- read_delim(file_path, delim = delimiter, col_types = column_types) %>%
    mutate(biogeo = biogeo, unit = unit)
  
  # Reorder columns based on expected columns
  data <- data %>%
    select(all_of(expected_columns), everything())
  
  return(data)
}

# Read and merge all CSV files
data_RS_Landsat <- map_dfr(csv_files, read_and_label)

# View the resulting tibble
print(data_RS_Landsat)

# Counts per biogeo and unit
print(data_RS_Landsat %>% count(biogeo, unit), n = 100)

Data cleaning Landsat NDVI & NDMI

data_RS_Landsat <- data_RS_Landsat %>%
  # Keep the columns we need
  select(obs_unique, biogeo, unit, year, source, Lat_update, Lon_update,
         NDVI_max, NDMI_max) %>% # Keep only these two so far
  # Rename those as NDVI and NDMI to agree with S2 data
  rename(NDVI = NDVI_max, NDMI = NDMI_max) %>%
  # Rename Lat and Lon, these are only kept in case there is differrence with
  # those in the ReSurvey database due to updates based on Ilona's info
  rename(Lat_RS = Lat_update, Lon_RS = Lon_update) %>%
  # Same for year
  rename(year_RS = year)

Canopy height

data_RS_CH <- read_csv(
  "C:/Data/MOTIVATE/MOTIVATE_RS_data/Canopy_Height_1m/Europe_points_CanopyHeight_1m.csv")
Rows: 425310 Columns: 8── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): system:index, .geo
dbl (6): Lat_update, Lon_update, canopy_height, obs_unique, plot_uniqu, year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
data_RS_CH

Data cleaning CH

data_RS_CH <- data_RS_CH %>%
  # Keep the columns we need
  select(obs_unique, canopy_height)

TBD: Biomass

Read file db_Europa

In this file, there is the correspondence obs_unique - PlotObservationID.

db_Europa <- read_csv(
  here("..", "DB_first_check", "data", "clean","db_Europa_20250107.csv")
  )
Rows: 425310 Columns: 12── Column specification ────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (6): Country, RS_CODE, ReSurvey site, ReSurvey plot, Expert System, Location method
dbl (6): PlotObservationID, Lon_updated, Lat_updated, plot_unique_id, year, obs_unique_id
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Get only the columns PlotObservationID (original unique identifier) obs_unique_id (unique identified created by me) and year.

db_Europa <- db_Europa %>% select(PlotObservationID, obs_unique_id)

Merge RS data and db_Europa

data_RS_S2_ID <- db_Europa %>%
  right_join(data_RS_S2 %>%
              # Rename to be able to join on this column
              rename(obs_unique_id = obs_unique))
Joining with `by = join_by(obs_unique_id)`

Now we have PlotObservationID in data_RS_S2_ID.

data_RS_S2_phen_ID <- db_Europa %>%
  right_join(data_RS_S2_phen %>%
              # Rename to be able to join on this column
              rename(obs_unique_id = obs_unique))
Joining with `by = join_by(obs_unique_id)`

Now we have PlotObservationID in data_RS_S2_phen_ID

data_RS_Landsat_ID <- db_Europa %>%
  right_join(data_RS_Landsat %>%
              # Rename to be able to join on this column
              rename(obs_unique_id = obs_unique))
Joining with `by = join_by(obs_unique_id)`

Now we have PlotObservationID in data_RS_Landsat_ID.

data_RS_CH_ID <- db_Europa %>%
  right_join(data_RS_CH %>%
              # Rename to be able to join on this column
              rename(obs_unique_id = obs_unique))
Joining with `by = join_by(obs_unique_id)`

Now we have PlotObservationID in data_RS_CH_ID.

Read file db_resurv_updated_clean

This is the ReSurvey database after updates (to be continued).

db_resurv <- read_tsv(
  here("..", "DB_first_check","data", "clean","db_resurv_updated_clean.csv"),
  col_types = cols(
    # Dynamically specify EUNIS columns as character
    .default = col_guess(),  # Default guessing for other columns
    EUNISa = col_character(),
    EUNISb = col_character(),
    EUNISc = col_character(),
    EUNISd = col_character(),
    EUNISa_1 = col_character(),
    EUNISa_2 = col_character(),
    EUNISa_3 = col_character(),
    EUNISa_4 = col_character(),
    EUNISb_1 = col_character(),
    EUNISb_2 = col_character(),
    EUNISb_3 = col_character(),
    EUNISb_4 = col_character(),
    EUNISc_1 = col_character(),
    EUNISc_2 = col_character(),
    EUNISc_3 = col_character(),
    EUNISc_4 = col_character(),
    EUNISd_1 = col_character(),
    EUNISd_2 = col_character(),
    EUNISd_3 = col_character(),
    EUNISd_4 = col_character(),
    EUNISa_1_descr = col_character(),
    EUNISb_1_descr = col_character(),
    EUNISc_1_descr = col_character(),
    EUNISd_1_descr = col_character(),
    EUNIS_assignation = col_character(),
    EUNISa_2_descr = col_character(),
    EUNISa_3_descr = col_character(),
    EUNISa_4_descr = col_character(),
    EUNISb_2_descr = col_character(),
    EUNISb_3_descr = col_character(),
    EUNISb_4_descr = col_character(),
    EUNISc_2_descr = col_character(),
    EUNISc_3_descr = col_character(),
    EUNISc_4_descr = col_character(),
    EUNISd_2_descr = col_character(),
    EUNISd_3_descr = col_character(),
    EUNISd_4_descr = col_character()
    )
  )

No parsing issues!

Merge RS data to the ReSurvey database

For some points, there is data (NDVI and NDMI so far) both from S2 and Landsat. In those cases, use the S2 data because it is more precise (10 m vs 30 m).

data_RS_S2_ID <- data_RS_S2_ID %>%
  rename(NDVI_S2 = NDVI, NDMI_S2 = NDMI) %>%
  select(-source)
data_RS_Landsat_ID <- data_RS_Landsat_ID %>%
  rename(NDVI_Landsat = NDVI, NDMI_Landsat = NDMI) %>%
  select(-source)

Join S2, S2_phen and Landsat data:

data_RS <- data_RS_S2_ID %>% 
  full_join(data_RS_S2_phen_ID) %>%
  full_join(data_RS_Landsat_ID)
Joining with `by = join_by(PlotObservationID, obs_unique_id, biogeo, unit)`Joining with `by = join_by(PlotObservationID, obs_unique_id, biogeo, unit, year_RS, Lat_RS, Lon_RS)`

Number of observations with NDVI data from both S2 and Landsat:

nrow(data_RS %>% filter(!is.na(NDVI_S2) & !is.na(NDVI_Landsat)))
[1] 493

Send points in .csv to Bea.

write.csv(data_RS %>% filter(!is.na(NDVI_S2) & !is.na(NDVI_Landsat)),
          file = here("data", "clean", "points_NDVI_S2_Landsat.csv"))

Difference between NDVI values from S2 and Landsat:

data_RS %>% filter(!is.na(NDVI_S2) & !is.na(NDVI_Landsat)) %>%
  mutate(diff_NDVI = NDVI_S2 - NDVI_Landsat) %>%
  ggplot(aes(x = diff_NDVI)) + geom_histogram(color = "black", fill = "white")

data_RS %>% filter(!is.na(NDMI_S2) & !is.na(NDMI_Landsat)) %>%
  mutate(diff_NDMI = NDMI_S2 - NDMI_Landsat) %>%
  ggplot(aes(x = diff_NDMI)) + geom_histogram(color = "black", fill = "white")

There is a large difference between NDVI values from S2 and Landsat. So far, use the S2 data, but check with Bea.

When NDVI and NDMI values are available from both satellites, use S2:

data_RS <- data_RS %>%
  mutate(NDVI =
           case_when(
             is.na(NDVI_S2) & is.na(NDVI_Landsat) ~ NA_real_,
             is.na(NDVI_Landsat) ~ NDVI_S2,
             is.na(NDVI_S2) ~ NDVI_Landsat,
             TRUE ~ NDVI_S2),
         NDMI = 
           case_when(
             is.na(NDMI_S2) & is.na(NDMI_Landsat) ~ NA_real_,
             is.na(NDMI_Landsat) ~ NDMI_S2,
             is.na(NDMI_S2) ~ NDMI_Landsat,
             TRUE ~ NDMI_S2),
         )
db_resurv_RS <- db_resurv %>%
  left_join(data_RS %>% select(-obs_unique_id)) %>%
  left_join(data_RS_CH_ID %>% select(-obs_unique_id)) %>%
  mutate(S2_data = !is.na(NDVI_S2) & !is.na(NDMI_S2), 
         Landsat_data = !is.na(NDVI_Landsat) & !is.na(NDMI_Landsat),
         CH_data = !is.na(canopy_height))
Joining with `by = join_by(PlotObservationID)`Joining with `by = join_by(PlotObservationID)`
db_resurv_RS %>% count(S2_data)
db_resurv_RS %>% count(Landsat_data)
db_resurv_RS %>% count(CH_data)

Save to clean data

Save clean file for analyses (to be updated continuously due to updates in ReSurvey database and updates on RS data).

write_tsv(db_resurv_RS,here("data", "clean","db_resurv_RS_20250327.csv"))

Session info

sessionInfo()
R version 4.4.2 (2024-10-31 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 26100)

Matrix products: default


locale:
[1] LC_COLLATE=Spanish_Spain.utf8  LC_CTYPE=Spanish_Spain.utf8    LC_MONETARY=Spanish_Spain.utf8
[4] LC_NUMERIC=C                   LC_TIME=Spanish_Spain.utf8    

time zone: Europe/Madrid
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] randomForestExplainer_0.10.1 pROC_1.18.5                  caret_7.0-1                 
 [4] lattice_0.22-6               randomForest_4.7-1.2         rnaturalearth_1.0.1         
 [7] sf_1.0-19                    scales_1.3.0                 readxl_1.4.3                
[10] gridExtra_2.3                here_1.0.1                   lubridate_1.9.4             
[13] forcats_1.0.0                stringr_1.5.1                dplyr_1.1.4                 
[16] purrr_1.0.2                  readr_2.1.5                  tidyr_1.3.1                 
[19] tibble_3.2.1                 ggplot2_3.5.1                tidyverse_2.0.0             

loaded via a namespace (and not attached):
 [1] DBI_1.2.3               rlang_1.1.5             magrittr_2.0.3          e1071_1.7-16           
 [5] compiler_4.4.2          reshape2_1.4.4          systemfonts_1.2.1       vctrs_0.6.5            
 [9] pkgconfig_2.0.3         crayon_1.5.3            fastmap_1.2.0           labeling_0.4.3         
[13] utf8_1.2.4              rmarkdown_2.29          prodlim_2024.06.25      tzdb_0.4.0             
[17] ragg_1.3.3              bit_4.5.0.1             xfun_0.50               cachem_1.1.0           
[21] jsonlite_1.8.9          recipes_1.1.1           terra_1.8-15            parallel_4.4.2         
[25] R6_2.5.1                RColorBrewer_1.1-3      bslib_0.9.0             stringi_1.8.4          
[29] GGally_2.2.1            parallelly_1.42.0       pkgload_1.4.0           rpart_4.1.23           
[33] jquerylib_0.1.4         cellranger_1.1.0        Rcpp_1.0.14             iterators_1.0.14       
[37] knitr_1.49              future.apply_1.11.3     Matrix_1.7-1            splines_4.4.2          
[41] nnet_7.3-19             timechange_0.3.0        tidyselect_1.2.1        rstudioapi_0.17.1      
[45] yaml_2.3.10             timeDate_4041.110       codetools_0.2-20        listenv_0.9.1          
[49] plyr_1.8.9              withr_3.0.2             evaluate_1.0.3          future_1.34.0          
[53] survival_3.7-0          ggstats_0.8.0           rnaturalearthdata_1.0.0 units_0.8-5            
[57] proxy_0.4-27            pillar_1.10.1           KernSmooth_2.23-24      DT_0.33                
[61] stats4_4.4.2            foreach_1.5.2           generics_0.1.3          vroom_1.6.5            
[65] rprojroot_2.0.4         hms_1.1.3               munsell_0.5.1           globals_0.16.3         
[69] class_7.3-22            glue_1.8.0              tools_4.4.2             data.table_1.16.4      
[73] ModelMetrics_1.2.2.2    gower_1.0.2             grid_4.4.2              ipred_0.9-15           
[77] colorspace_2.1-1        nlme_3.1-166            cli_3.6.3               textshaping_1.0.0      
[81] viridisLite_0.4.2       lava_1.8.1              gtable_0.3.6            sass_0.4.9             
[85] digest_0.6.37           classInt_0.4-11         ggrepel_0.9.6           htmlwidgets_1.6.4      
[89] farver_2.1.2            htmltools_0.5.8.1       lifecycle_1.0.4         hardhat_1.4.1          
[93] httr_1.4.7              bit64_4.6.0-1           MASS_7.3-61            
LS0tDQp0aXRsZTogIlNjcmlwdCB0byBtZXJnZSBhbGwgUlMgZGF0YSINCmF1dGhvcjogIkFsaWNpYSBWYWxkw6lzIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIgJVknKWAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIFIgc2NyaXB0IGlzIHVzZWQgdG8gbWVyZ2UgUlMgZGF0YSBkb3dubG9hZGVkIHRoZSBHb29nbGUgRHJpdmUgZm9sZGVyIHNoYXJlZCBieSBCZWEgd2l0aCB0aGUgUmVTdXJ2ZXkgZGF0YWJhc2UuDQoNCiMgTG9hZCBsaWJyYXJpZXMNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoaGVyZSkNCmBgYA0KDQojIFJlYWQgZmlsZXMgd2l0aCBSUyBkYXRhIGZyb20gQmVhDQoNCiMjIFMyIA0KDQojIyMgTkRWSSAmIE5ETUkNCg0KIyMjIE5PVEU6IFRvIGJlIHVwZGF0ZWQgd2l0aCBmaWxlcyBpbiBmb2xkZXJzICJOZXdfZmlsdGVyIg0KDQpgYGB7cn0NCiMgU2V0IHRoZSBmb2xkZXIgcGF0aA0KZm9sZGVyX3BhdGggPC0gIkM6L0RhdGEvTU9USVZBVEUvTU9USVZBVEVfUlNfZGF0YS9TMiINCg0KIyBMaXN0IG9ubHkgQ1NWIGZpbGVzIHRoYXQgY29udGFpbiAibWF4X0ZpbHRlcmVkIiBpbiB0aGVpciBmaWxlbmFtZQ0KY3N2X2ZpbGVzIDwtIGxpc3QuZmlsZXMoZm9sZGVyX3BhdGgsIHBhdHRlcm4gPSAibWF4X0ZpbHRlcmVkLipcXC5jc3YkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUUlVFLCByZWN1cnNpdmUgPSBUUlVFKQ0KDQojIEZ1bmN0aW9uIHRvIHJlYWQgZWFjaCBmaWxlIGFuZCBleHRyYWN0IGluZm8gZnJvbSB0aGUgZmlsZW5hbWUNCnJlYWRfYW5kX2xhYmVsIDwtIGZ1bmN0aW9uKGZpbGVfcGF0aCkgew0KICBmaWxlX25hbWUgPC0gYmFzZW5hbWUoZmlsZV9wYXRoKQ0KICANCiAgIyBFeHRyYWN0IHJlZ2lvbiBhbmQgc3VicmVnaW9uIGZyb20gdGhlIGZpbGVuYW1lDQogICMgVXBkYXRlZCByZWd1bGFyIGV4cHJlc3Npb24gdG8gaGFuZGxlIHRoZSBjYXNlIHdoZXJlIHN1YnJlZ2lvbiBpcyBtaXNzaW5nDQogIGNvbXBvbmVudHMgPC0gc3RyX21hdGNoKGZpbGVfbmFtZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIl5bMC05X10qKFteX10rKV8oW15fXSspX1NlbnRpbmVsLio/XyguKj8pLmNzdiIpDQogIA0KICAjIEV4dHJhY3QgdGhlIGJpb2dlbyBhbmQgdW5pdCwgaGFuZGxpbmcgbWlzc2luZyBzdWJyZWdpb24gKHVuaXQpDQogIGJpb2dlbyA8LSBjb21wb25lbnRzWzJdDQogIA0KICAjIElmIHN1YnJlZ2lvbiAodW5pdCkgaXMgbWlzc2luZywgc2V0IGl0IGFzIE5BDQogIHVuaXQgPC0gaWZlbHNlKGlzLm5hKGNvbXBvbmVudHNbM10pLCBOQSwgY29tcG9uZW50c1szXSkNCiAgDQogICMgQ2hlY2sgaWYgYmlvZ2VvIGlzIG1pc3NpbmcsIGFuZCBpZiBzbywNCiAgIyBhc3NpZ24gdGhlIGZpcnN0IHBhcnQgb2YgdGhlIGZpbGVuYW1lIChyZWdpb24gbmFtZSkNCiAgaWYgKGlzLm5hKGJpb2dlbykgJiYgZ3JlcGwoIlNlbnRpbmVsIiwgZmlsZV9uYW1lKSkgew0KICAgICMgQ2FwdHVyZSB0aGUgZmlyc3QgcGFydCAoYmlvZ2VvKSBkaXJlY3RseQ0KICAgIGJpb2dlbyA8LSBzdHJfbWF0Y2goZmlsZV9uYW1lLCAiXlswLTlfXSooW15fXSspX1NlbnRpbmVsIilbMl0NCiAgfQ0KICANCiAgIyBJZiBiaW9nZW8gaXMgc3RpbGwgTkEsIHByaW50IGEgd2FybmluZw0KICBpZiAoaXMubmEoYmlvZ2VvKSkgew0KICAgIHdhcm5pbmcocGFzdGUoIkZhaWxlZCB0byBleHRyYWN0IGJpb2dlbyBmb3IgZmlsZToiLCBmaWxlX25hbWUpKQ0KICB9DQoNCiAgIyBSZWFkIENTViBhbmQgYWRkIGNvbHVtbnMgZm9yIGV4dHJhY3RlZCBpbmZvDQogIHJlYWRfY3N2KGZpbGVfcGF0aCkgJT4lDQogICAgbXV0YXRlKGJpb2dlbyA9IGJpb2dlbywgdW5pdCA9IHVuaXQpDQp9DQojIFJlYWQgYW5kIG1lcmdlIGFsbCBDU1YgZmlsZXMNCmRhdGFfUlNfUzIgPC0gbWFwX2Rmcihjc3ZfZmlsZXMsIHJlYWRfYW5kX2xhYmVsKQ0KDQojIFZpZXcgdGhlIHJlc3VsdGluZyB0aWJibGUNCnByaW50KGRhdGFfUlNfUzIpDQoNCiMgQ291bnRzIHBlciBiaW9nZW8gYW5kIHVuaXQNCnByaW50KGRhdGFfUlNfUzIgJT4lIGNvdW50KGJpb2dlbywgdW5pdCksIG4gPSAxMDApDQpgYGANCg0KIyMjIyBEYXRhIGNsZWFuaW5nIFMyIE5EVkkgJiBORE1JDQoNCmBgYHtyfQ0KZGF0YV9SU19TMiA8LSBkYXRhX1JTX1MyICU+JQ0KICAjIEtlZXAgdGhlIGNvbHVtbnMgd2UgbmVlZA0KICBzZWxlY3Qob2JzX3VuaXF1ZSwgYmlvZ2VvLCB1bml0LCB5ZWFyLCBzb3VyY2UsIExhdF91cGRhdGUsIExvbl91cGRhdGUsDQogICAgICAgICBORFZJLCBORE1JKSAlPiUNCiAgIyBSZW5hbWUgTGF0IGFuZCBMb24sIHRoZXNlIGFyZSBvbmx5IGtlcHQgaW4gY2FzZSB0aGVyZSBpcyBkaWZmZXJlbmNlIHdpdGgNCiAgIyB0aG9zZSBpbiB0aGUgUmVTdXJ2ZXkgZGF0YWJhc2UgZHVlIHRvIHVwZGF0ZXMgYmFzZWQgb24gSWxvbmEncyBpbmZvDQogIHJlbmFtZShMYXRfUlMgPSBMYXRfdXBkYXRlLCBMb25fUlMgPSBMb25fdXBkYXRlKSAlPiUNCiAgIyBTYW1lIGZvciB5ZWFyDQogIHJlbmFtZSh5ZWFyX1JTID0geWVhcikNCmBgYA0KDQojIyMgU09TLCBQZWFrIGFuZCBFT1MNCg0KYGBge3J9DQojIFNldCB0aGUgZm9sZGVyIHBhdGgNCmZvbGRlcl9wYXRoIDwtICJDOi9EYXRhL01PVElWQVRFL01PVElWQVRFX1JTX2RhdGEvUzIiDQoNCiMgTGlzdCBvbmx5IENTViBmaWxlcyB0aGF0IGNvbnRhaW4gIk5EVklfUGhlbm9sb2d5IiBpbiB0aGVpciBmaWxlbmFtZQ0KY3N2X2ZpbGVzIDwtIGxpc3QuZmlsZXMoZm9sZGVyX3BhdGgsIHBhdHRlcm4gPSAiTkRWSV9QaGVub2xvZ3kuKlxcLmNzdiQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFRSVUUsIHJlY3Vyc2l2ZSA9IFRSVUUpDQoNCiMgRnVuY3Rpb24gdG8gcmVhZCBlYWNoIGZpbGUgYW5kIGV4dHJhY3QgaW5mbyBmcm9tIHRoZSBmaWxlbmFtZQ0KcmVhZF9hbmRfbGFiZWwgPC0gZnVuY3Rpb24oZmlsZV9wYXRoKSB7DQogIGZpbGVfbmFtZSA8LSBiYXNlbmFtZShmaWxlX3BhdGgpDQogIA0KICAjIEV4dHJhY3QgcmVnaW9uIGFuZCBzdWJyZWdpb24gZnJvbSB0aGUgZmlsZW5hbWUNCiAgIyBVcGRhdGVkIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBoYW5kbGUgdGhlIGNhc2Ugd2hlcmUgc3VicmVnaW9uIGlzIG1pc3NpbmcNCiAgY29tcG9uZW50cyA8LSBzdHJfbWF0Y2goZmlsZV9uYW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiXlswLTlfXSooW15fXSspXyhbXl9dKylfTkRWSV9QaGVub2xvZ3kuKj9fKC4qPykuY3N2IikNCiAgDQogICMgRXh0cmFjdCB0aGUgYmlvZ2VvIGFuZCB1bml0LCBoYW5kbGluZyBtaXNzaW5nIHN1YnJlZ2lvbiAodW5pdCkNCiAgYmlvZ2VvIDwtIGNvbXBvbmVudHNbMl0NCiAgDQogICMgSWYgc3VicmVnaW9uICh1bml0KSBpcyBtaXNzaW5nLCBzZXQgaXQgYXMgTkENCiAgdW5pdCA8LSBpZmVsc2UoaXMubmEoY29tcG9uZW50c1szXSksIE5BLCBjb21wb25lbnRzWzNdKQ0KICANCiAgIyBDaGVjayBpZiBiaW9nZW8gaXMgbWlzc2luZywgYW5kIGlmIHNvLA0KICAjIGFzc2lnbiB0aGUgZmlyc3QgcGFydCBvZiB0aGUgZmlsZW5hbWUgKHJlZ2lvbiBuYW1lKQ0KICBpZiAoaXMubmEoYmlvZ2VvKSAmJiBncmVwbCgiX05EVklfUGhlbm9sb2d5IiwgZmlsZV9uYW1lKSkgew0KICAgICMgQ2FwdHVyZSB0aGUgZmlyc3QgcGFydCAoYmlvZ2VvKSBkaXJlY3RseQ0KICAgIGJpb2dlbyA8LSBzdHJfbWF0Y2goZmlsZV9uYW1lLCAiXlswLTlfXSooW15fXSspX05EVklfUGhlbm9sb2d5IilbMl0NCiAgfQ0KICANCiAgIyBJZiBiaW9nZW8gaXMgc3RpbGwgTkEsIHByaW50IGEgd2FybmluZw0KICBpZiAoaXMubmEoYmlvZ2VvKSkgew0KICAgIHdhcm5pbmcocGFzdGUoIkZhaWxlZCB0byBleHRyYWN0IGJpb2dlbyBmb3IgZmlsZToiLCBmaWxlX25hbWUpKQ0KICB9DQoNCiAgIyBSZWFkIENTViBhbmQgYWRkIGNvbHVtbnMgZm9yIGV4dHJhY3RlZCBpbmZvDQogIHJlYWRfY3N2KGZpbGVfcGF0aCkgJT4lDQogICAgbXV0YXRlKGJpb2dlbyA9IGJpb2dlbywgdW5pdCA9IHVuaXQpDQp9DQojIFJlYWQgYW5kIG1lcmdlIGFsbCBDU1YgZmlsZXMNCmRhdGFfUlNfUzJfcGhlbiA8LSBtYXBfZGZyKGNzdl9maWxlcywgcmVhZF9hbmRfbGFiZWwpDQoNCiMgVmlldyB0aGUgcmVzdWx0aW5nIHRpYmJsZQ0KcHJpbnQoZGF0YV9SU19TMl9waGVuKQ0KDQojIENvdW50cyBwZXIgYmlvZ2VvIGFuZCB1bml0DQpwcmludChkYXRhX1JTX1MyX3BoZW4gJT4lIGNvdW50KGJpb2dlbywgdW5pdCksIG4gPSAxMDApDQpgYGANCg0KIyMjIyBEYXRhIGNsZWFuaW5nIFMyIFNPUywgUGVhayBhbmQgRU9TDQoNCmBgYHtyfQ0KZGF0YV9SU19TMl9waGVuIDwtIGRhdGFfUlNfUzJfcGhlbiAlPiUNCiAgIyBLZWVwIHRoZSBjb2x1bW5zIHdlIG5lZWQNCiAgc2VsZWN0KG9ic191bmlxdWUsIGJpb2dlbywgdW5pdCwgU09TX0RPWSwgU09TX0RhdGUsIFBlYWtfRE9ZLCBQZWFrX0RhdGUsDQogICAgICAgICBFT1NfRE9ZLCBFT1NfRGF0ZSkNCiAgIyBSZW1vdmUgTGF0IGFuZCBMb24gYW5kIHllYXIsIGluIGNhc2UgdGhlcmUgaXMgZGlmZmVyZW5jZSB3aXRoDQogICMgdGhvc2UgaW4gdGhlIFJlU3VydmV5IGRhdGFiYXNlIGR1ZSB0byB1cGRhdGVzIGJhc2VkIG9uIElsb25hJ3MgaW5mbywNCiAgIyB3ZSBoYXZlIExhdF9SUywgTG9uX1JTIGFuZCB5ZWFyX1JTIGZyb20gZGF0YV9SU19TMg0KYGBgDQoNCiMjIExhbmRzYXQNCg0KIyMjIE5EVkksIE5ETUkgJiBvdGhlciBzdHVmZg0KDQojIyMgTk9URTogc29tZSByZWdpb25zIG1pc3NpbmcgKGF0IGxlYXN0IENPTikNCg0KYGBge3J9DQojIFNldCB0aGUgZm9sZGVyIHBhdGgNCmZvbGRlcl9wYXRoIDwtICJDOi9EYXRhL01PVElWQVRFL01PVElWQVRFX1JTX2RhdGEvTGFuZHNhdCINCg0KIyBMaXN0IG9ubHkgQ1NWIGZpbGVzIHRoYXQgY29udGFpbiAiUGxvdCIgaW4gdGhlaXIgZmlsZW5hbWUNCmNzdl9maWxlcyA8LSBsaXN0LmZpbGVzKGZvbGRlcl9wYXRoLCBwYXR0ZXJuID0gIlBsb3QuKlxcLmNzdiQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFRSVUUsIHJlY3Vyc2l2ZSA9IFRSVUUpDQoNCiMgUmVtb3ZlIEFMUF9CQUwgc28gZmFyIGNhdXNlIHRoZXJlIHNlZW1zIHRvIGJlIGFuIGVycm9yIGluIHRoYXQgdGFibGUNCg0KY3N2X2ZpbGVzIDwtIGNzdl9maWxlc1stMV0gDQoNCiMgRGVmaW5lIHRoZSBleHBlY3RlZCBjb2x1bW4gbmFtZXMNCmV4cGVjdGVkX2NvbHVtbnMgPC0gYygic3lzdGVtOmluZGV4IiwgIkxhdF91cGRhdGUiLCAiTG9uX3VwZGF0ZSIsICJvYnNfdW5pcXVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAicGxvdF91bmlxdSIsCSJzb3VyY2UiLAkieWVhciIsCSJFVklfbWF4IiwJIkVWSV9tZWRpYW4iLA0KICAgICAgICAgICAgICAgICAgICAgICJFVklfbWluIiwgIkVWSV9wMTAiLAkiRVZJX3A5MCIsCSJFVklfc3RkRGV2IiwJIkVWSW1lYW4iLA0KICAgICAgICAgICAgICAgICAgICAgICJORE1JX21heCIsCSJORE1JX21lZGlhbiIsCSJORE1JX21pbiIsCSJORE1JX3AxMCIsDQogICAgICAgICAgICAgICAgICAgICAgIk5ETUlfcDkwIiwJIk5ETUlfc3RkRGV2IiwJIk5ETUltZWFuIiwJIk5EVklfbWF4IiwNCiAgICAgICAgICAgICAgICAgICAgICAiTkRWSV9tZWRpYW4iLAkiTkRWSV9taW4iLAkiTkRWSV9wMTAiLAkiTkRWSV9wOTAiLA0KICAgICAgICAgICAgICAgICAgICAgICJORFZJX3N0ZERldiIsCSJORFZJbWVhbiIsCSJORFdJX21heCIsCSJORFdJX21lZGlhbiIsDQogICAgICAgICAgICAgICAgICAgICAgIk5EV0lfbWluIiwJIk5EV0lfcDEwIiwJIk5EV0lfcDkwIiwJIk5EV0lfc3RkRGV2IiwNCiAgICAgICAgICAgICAgICAgICAgICAiTkRXSW1lYW4iLAkiU0FWSV9tYXgiLAkiU0FWSV9tZWRpYW4iLAkiU0FWSV9taW4iLA0KICAgICAgICAgICAgICAgICAgICAgICJTQVZJX3AxMCIsCSJTQVZJX3A5MCIsCSJTQVZJX3N0ZERldiIsCSJTQVZJbWVhbiIsCSIuZ2VvIikgDQoNCiMgRGVmaW5lIHRoZSBjb2x1bW4gdHlwZXMNCmNvbHVtbl90eXBlcyA8LSBjb2xzKA0KICBgc3lzdGVtOmluZGV4YCA9IGNvbF9jaGFyYWN0ZXIoKSwgTGF0X3VwZGF0ZSA9IGNvbF9kb3VibGUoKSwNCiAgTG9uX3VwZGF0ZSA9IGNvbF9kb3VibGUoKSwgb2JzX3VuaXF1ZSA9IGNvbF9kb3VibGUoKSwNCiAgcGxvdF91bmlxdSA9IGNvbF9jaGFyYWN0ZXIoKSwgc291cmNlID0gY29sX2NoYXJhY3RlcigpLCB5ZWFyID0gY29sX2ludGVnZXIoKSwNCiAgRVZJX21heCA9IGNvbF9kb3VibGUoKSwgRVZJX21lZGlhbiA9IGNvbF9kb3VibGUoKSwgRVZJX21pbiA9IGNvbF9kb3VibGUoKSwNCiAgRVZJX3AxMCA9IGNvbF9kb3VibGUoKSwgRVZJX3A5MCA9IGNvbF9kb3VibGUoKSwgRVZJX3N0ZERldiA9IGNvbF9kb3VibGUoKSwNCiAgRVZJbWVhbiA9IGNvbF9kb3VibGUoKSwgTkRNSV9tYXggPSBjb2xfZG91YmxlKCksIE5ETUlfbWVkaWFuID0gY29sX2RvdWJsZSgpLA0KICBORE1JX21pbiA9IGNvbF9kb3VibGUoKSwgTkRNSV9wMTAgPSBjb2xfZG91YmxlKCksIE5ETUlfcDkwID0gY29sX2RvdWJsZSgpLA0KICBORE1JX3N0ZERldiA9IGNvbF9kb3VibGUoKSwgTkRNSW1lYW4gPSBjb2xfZG91YmxlKCksIE5EVklfbWF4ID0gY29sX2RvdWJsZSgpLA0KICBORFZJX21lZGlhbiA9IGNvbF9kb3VibGUoKSwgTkRWSV9taW4gPSBjb2xfZG91YmxlKCksIE5EVklfcDEwID0gY29sX2RvdWJsZSgpLA0KICBORFZJX3A5MCA9IGNvbF9kb3VibGUoKSwgTkRWSV9zdGREZXYgPSBjb2xfZG91YmxlKCksIE5EVkltZWFuID0gY29sX2RvdWJsZSgpLA0KICBORFdJX21heCA9IGNvbF9kb3VibGUoKSwgTkRXSV9tZWRpYW4gPSBjb2xfZG91YmxlKCksIE5EV0lfbWluID0gY29sX2RvdWJsZSgpLA0KICBORFdJX3AxMCA9IGNvbF9kb3VibGUoKSwgTkRXSV9wOTAgPSBjb2xfZG91YmxlKCksIE5EV0lfc3RkRGV2ID0gY29sX2RvdWJsZSgpLA0KICBORFdJbWVhbiA9IGNvbF9kb3VibGUoKSwgU0FWSV9tYXggPSBjb2xfZG91YmxlKCksIFNBVklfbWVkaWFuID0gY29sX2RvdWJsZSgpLA0KICBTQVZJX21pbiA9IGNvbF9kb3VibGUoKSwgU0FWSV9wMTAgPSBjb2xfZG91YmxlKCksIFNBVklfcDkwID0gY29sX2RvdWJsZSgpLA0KICBTQVZJX3N0ZERldiA9IGNvbF9kb3VibGUoKSwgU0FWSW1lYW4gPSBjb2xfZG91YmxlKCksIC5nZW8gPSBjb2xfY2hhcmFjdGVyKCkNCikNCg0KIyBGdW5jdGlvbiB0byByZWFkIGVhY2ggZmlsZSBhbmQgZXh0cmFjdCBpbmZvIGZyb20gdGhlIGZpbGVuYW1lDQpyZWFkX2FuZF9sYWJlbCA8LSBmdW5jdGlvbihmaWxlX3BhdGgpIHsNCiAgZmlsZV9uYW1lIDwtIGJhc2VuYW1lKGZpbGVfcGF0aCkNCiAgDQogICMgRXh0cmFjdCByZWdpb24gYW5kIHN1YnJlZ2lvbiBmcm9tIHRoZSBmaWxlbmFtZQ0KICAjIFVwZGF0ZWQgcmVndWxhciBleHByZXNzaW9uIHRvIGhhbmRsZSB0aGUgY2FzZSB3aGVyZSBzdWJyZWdpb24gaXMgbWlzc2luZw0KICBjb21wb25lbnRzIDwtIHN0cl9tYXRjaChmaWxlX25hbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJeWzAtOV9dKihbXl9dKylfKFteX10rKV9MYW5kc2F0Lio/XyguKj8pLmNzdiIpDQogIA0KICAjIEV4dHJhY3QgdGhlIGJpb2dlbyBhbmQgdW5pdCwgaGFuZGxpbmcgbWlzc2luZyBzdWJyZWdpb24gKHVuaXQpDQogIGJpb2dlbyA8LSBjb21wb25lbnRzWzJdDQogIA0KICAjIElmIHN1YnJlZ2lvbiAodW5pdCkgaXMgbWlzc2luZywgc2V0IGl0IGFzIE5BDQogIHVuaXQgPC0gaWZlbHNlKGlzLm5hKGNvbXBvbmVudHNbM10pLCBOQSwgY29tcG9uZW50c1szXSkNCiAgDQogICMgQ2hlY2sgaWYgYmlvZ2VvIGlzIG1pc3NpbmcsIGFuZCBpZiBzbywNCiAgIyBhc3NpZ24gdGhlIGZpcnN0IHBhcnQgb2YgdGhlIGZpbGVuYW1lIChyZWdpb24gbmFtZSkNCiAgaWYgKGlzLm5hKGJpb2dlbykgJiYgZ3JlcGwoIkxhbmRzYXQiLCBmaWxlX25hbWUpKSB7DQogICAgIyBDYXB0dXJlIHRoZSBmaXJzdCBwYXJ0IChiaW9nZW8pIGRpcmVjdGx5DQogICAgYmlvZ2VvIDwtIHN0cl9tYXRjaChmaWxlX25hbWUsICJeWzAtOV9dKihbXl9dKylfTGFuZHNhdCIpWzJdDQogIH0NCiAgDQogICMgSWYgYmlvZ2VvIGlzIHN0aWxsIE5BLCBwcmludCBhIHdhcm5pbmcNCiAgaWYgKGlzLm5hKGJpb2dlbykpIHsNCiAgICB3YXJuaW5nKHBhc3RlKCJGYWlsZWQgdG8gZXh0cmFjdCBiaW9nZW8gZm9yIGZpbGU6IiwgZmlsZV9uYW1lKSkNCiAgfQ0KICANCiAgZGVsaW1pdGVyIDwtIGlmZWxzZShncmVwbCgiOyIsIHJlYWRMaW5lcyhmaWxlX3BhdGgsIG4gPSAxKSksICI7IiwgIiwiKQ0KICANCiAgIyBSZWFkIENTViBhbmQgYWRkIGNvbHVtbnMgZm9yIGV4dHJhY3RlZCBpbmZvDQogIGRhdGEgPC0gcmVhZF9kZWxpbShmaWxlX3BhdGgsIGRlbGltID0gZGVsaW1pdGVyLCBjb2xfdHlwZXMgPSBjb2x1bW5fdHlwZXMpICU+JQ0KICAgIG11dGF0ZShiaW9nZW8gPSBiaW9nZW8sIHVuaXQgPSB1bml0KQ0KICANCiAgIyBSZW9yZGVyIGNvbHVtbnMgYmFzZWQgb24gZXhwZWN0ZWQgY29sdW1ucw0KICBkYXRhIDwtIGRhdGEgJT4lDQogICAgc2VsZWN0KGFsbF9vZihleHBlY3RlZF9jb2x1bW5zKSwgZXZlcnl0aGluZygpKQ0KICANCiAgcmV0dXJuKGRhdGEpDQp9DQoNCiMgUmVhZCBhbmQgbWVyZ2UgYWxsIENTViBmaWxlcw0KZGF0YV9SU19MYW5kc2F0IDwtIG1hcF9kZnIoY3N2X2ZpbGVzLCByZWFkX2FuZF9sYWJlbCkNCg0KIyBWaWV3IHRoZSByZXN1bHRpbmcgdGliYmxlDQpwcmludChkYXRhX1JTX0xhbmRzYXQpDQoNCiMgQ291bnRzIHBlciBiaW9nZW8gYW5kIHVuaXQNCnByaW50KGRhdGFfUlNfTGFuZHNhdCAlPiUgY291bnQoYmlvZ2VvLCB1bml0KSwgbiA9IDEwMCkNCmBgYA0KDQojIyMjIERhdGEgY2xlYW5pbmcgTGFuZHNhdCBORFZJICYgTkRNSQ0KDQpgYGB7cn0NCmRhdGFfUlNfTGFuZHNhdCA8LSBkYXRhX1JTX0xhbmRzYXQgJT4lDQogICMgS2VlcCB0aGUgY29sdW1ucyB3ZSBuZWVkDQogIHNlbGVjdChvYnNfdW5pcXVlLCBiaW9nZW8sIHVuaXQsIHllYXIsIHNvdXJjZSwgTGF0X3VwZGF0ZSwgTG9uX3VwZGF0ZSwNCiAgICAgICAgIE5EVklfbWF4LCBORE1JX21heCkgJT4lICMgS2VlcCBvbmx5IHRoZXNlIHR3byBzbyBmYXINCiAgIyBSZW5hbWUgdGhvc2UgYXMgTkRWSSBhbmQgTkRNSSB0byBhZ3JlZSB3aXRoIFMyIGRhdGENCiAgcmVuYW1lKE5EVkkgPSBORFZJX21heCwgTkRNSSA9IE5ETUlfbWF4KSAlPiUNCiAgIyBSZW5hbWUgTGF0IGFuZCBMb24sIHRoZXNlIGFyZSBvbmx5IGtlcHQgaW4gY2FzZSB0aGVyZSBpcyBkaWZmZXJyZW5jZSB3aXRoDQogICMgdGhvc2UgaW4gdGhlIFJlU3VydmV5IGRhdGFiYXNlIGR1ZSB0byB1cGRhdGVzIGJhc2VkIG9uIElsb25hJ3MgaW5mbw0KICByZW5hbWUoTGF0X1JTID0gTGF0X3VwZGF0ZSwgTG9uX1JTID0gTG9uX3VwZGF0ZSkgJT4lDQogICMgU2FtZSBmb3IgeWVhcg0KICByZW5hbWUoeWVhcl9SUyA9IHllYXIpDQpgYGANCg0KIyMgQ2Fub3B5IGhlaWdodA0KDQpgYGB7cn0NCmRhdGFfUlNfQ0ggPC0gcmVhZF9jc3YoDQogICJDOi9EYXRhL01PVElWQVRFL01PVElWQVRFX1JTX2RhdGEvQ2Fub3B5X0hlaWdodF8xbS9FdXJvcGVfcG9pbnRzX0Nhbm9weUhlaWdodF8xbS5jc3YiKQ0KZGF0YV9SU19DSA0KYGBgDQoNCiMjIyBEYXRhIGNsZWFuaW5nIENIDQoNCmBgYHtyfQ0KZGF0YV9SU19DSCA8LSBkYXRhX1JTX0NIICU+JQ0KICAjIEtlZXAgdGhlIGNvbHVtbnMgd2UgbmVlZA0KICBzZWxlY3Qob2JzX3VuaXF1ZSwgY2Fub3B5X2hlaWdodCkNCmBgYA0KDQojIyBUQkQ6IEJpb21hc3MNCg0KIyBSZWFkIGZpbGUgZGJfRXVyb3BhDQoNCkluIHRoaXMgZmlsZSwgdGhlcmUgaXMgdGhlIGNvcnJlc3BvbmRlbmNlIG9ic191bmlxdWUgLSBQbG90T2JzZXJ2YXRpb25JRC4NCg0KYGBge3J9DQpkYl9FdXJvcGEgPC0gcmVhZF9jc3YoDQogIGhlcmUoIi4uIiwgIkRCX2ZpcnN0X2NoZWNrIiwgImRhdGEiLCAiY2xlYW4iLCJkYl9FdXJvcGFfMjAyNTAxMDcuY3N2IikNCiAgKQ0KYGBgDQoNCkdldCBvbmx5IHRoZSBjb2x1bW5zIFBsb3RPYnNlcnZhdGlvbklEIChvcmlnaW5hbCB1bmlxdWUgaWRlbnRpZmllcikgb2JzX3VuaXF1ZV9pZCAodW5pcXVlIGlkZW50aWZpZWQgY3JlYXRlZCBieSBtZSkgYW5kIHllYXIuDQoNCmBgYHtyfQ0KZGJfRXVyb3BhIDwtIGRiX0V1cm9wYSAlPiUgc2VsZWN0KFBsb3RPYnNlcnZhdGlvbklELCBvYnNfdW5pcXVlX2lkKQ0KYGBgDQoNCiMgTWVyZ2UgUlMgZGF0YSBhbmQgZGJfRXVyb3BhDQoNCmBgYHtyfQ0KZGF0YV9SU19TMl9JRCA8LSBkYl9FdXJvcGEgJT4lDQogIHJpZ2h0X2pvaW4oZGF0YV9SU19TMiAlPiUNCiAgICAgICAgICAgICAgIyBSZW5hbWUgdG8gYmUgYWJsZSB0byBqb2luIG9uIHRoaXMgY29sdW1uDQogICAgICAgICAgICAgIHJlbmFtZShvYnNfdW5pcXVlX2lkID0gb2JzX3VuaXF1ZSkpDQpgYGANCg0KTm93IHdlIGhhdmUgUGxvdE9ic2VydmF0aW9uSUQgaW4gZGF0YV9SU19TMl9JRC4NCg0KYGBge3J9DQpkYXRhX1JTX1MyX3BoZW5fSUQgPC0gZGJfRXVyb3BhICU+JQ0KICByaWdodF9qb2luKGRhdGFfUlNfUzJfcGhlbiAlPiUNCiAgICAgICAgICAgICAgIyBSZW5hbWUgdG8gYmUgYWJsZSB0byBqb2luIG9uIHRoaXMgY29sdW1uDQogICAgICAgICAgICAgIHJlbmFtZShvYnNfdW5pcXVlX2lkID0gb2JzX3VuaXF1ZSkpDQoNCmBgYA0KDQpOb3cgd2UgaGF2ZSBQbG90T2JzZXJ2YXRpb25JRCBpbiBkYXRhX1JTX1MyX3BoZW5fSUQNCg0KYGBge3J9DQpkYXRhX1JTX0xhbmRzYXRfSUQgPC0gZGJfRXVyb3BhICU+JQ0KICByaWdodF9qb2luKGRhdGFfUlNfTGFuZHNhdCAlPiUNCiAgICAgICAgICAgICAgIyBSZW5hbWUgdG8gYmUgYWJsZSB0byBqb2luIG9uIHRoaXMgY29sdW1uDQogICAgICAgICAgICAgIHJlbmFtZShvYnNfdW5pcXVlX2lkID0gb2JzX3VuaXF1ZSkpDQpgYGANCg0KTm93IHdlIGhhdmUgUGxvdE9ic2VydmF0aW9uSUQgaW4gZGF0YV9SU19MYW5kc2F0X0lELg0KDQpgYGB7cn0NCmRhdGFfUlNfQ0hfSUQgPC0gZGJfRXVyb3BhICU+JQ0KICByaWdodF9qb2luKGRhdGFfUlNfQ0ggJT4lDQogICAgICAgICAgICAgICMgUmVuYW1lIHRvIGJlIGFibGUgdG8gam9pbiBvbiB0aGlzIGNvbHVtbg0KICAgICAgICAgICAgICByZW5hbWUob2JzX3VuaXF1ZV9pZCA9IG9ic191bmlxdWUpKQ0KYGBgDQoNCk5vdyB3ZSBoYXZlIFBsb3RPYnNlcnZhdGlvbklEIGluIGRhdGFfUlNfQ0hfSUQuDQoNCiMgUmVhZCBmaWxlIGRiX3Jlc3Vydl91cGRhdGVkX2NsZWFuDQoNClRoaXMgaXMgdGhlIFJlU3VydmV5IGRhdGFiYXNlIGFmdGVyIHVwZGF0ZXMgKHRvIGJlIGNvbnRpbnVlZCkuDQoNCmBgYHtyfQ0KZGJfcmVzdXJ2IDwtIHJlYWRfdHN2KA0KICBoZXJlKCIuLiIsICJEQl9maXJzdF9jaGVjayIsImRhdGEiLCAiY2xlYW4iLCJkYl9yZXN1cnZfdXBkYXRlZF9jbGVhbi5jc3YiKSwNCiAgY29sX3R5cGVzID0gY29scygNCiAgICAjIER5bmFtaWNhbGx5IHNwZWNpZnkgRVVOSVMgY29sdW1ucyBhcyBjaGFyYWN0ZXINCiAgICAuZGVmYXVsdCA9IGNvbF9ndWVzcygpLCAgIyBEZWZhdWx0IGd1ZXNzaW5nIGZvciBvdGhlciBjb2x1bW5zDQogICAgRVVOSVNhID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYiA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2MgPSBjb2xfY2hhcmFjdGVyKCksDQogICAgRVVOSVNkID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV8xID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV8yID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV8zID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV80ID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl8xID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl8yID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl8zID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl80ID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY18xID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY18yID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY18zID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY180ID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF8xID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF8yID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF8zID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF80ID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV8xX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl8xX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY18xX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF8xX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTX2Fzc2lnbmF0aW9uID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV8yX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV8zX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYV80X2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl8yX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl8zX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTYl80X2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY18yX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY18zX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTY180X2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF8yX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF8zX2Rlc2NyID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZF80X2Rlc2NyID0gY29sX2NoYXJhY3RlcigpDQogICAgKQ0KICApDQpgYGANCg0KTm8gcGFyc2luZyBpc3N1ZXMhDQoNCiMgTWVyZ2UgUlMgZGF0YSB0byB0aGUgUmVTdXJ2ZXkgZGF0YWJhc2UNCg0KRm9yIHNvbWUgcG9pbnRzLCB0aGVyZSBpcyBkYXRhIChORFZJIGFuZCBORE1JIHNvIGZhcikgYm90aCBmcm9tIFMyIGFuZCBMYW5kc2F0LiBJbiB0aG9zZSBjYXNlcywgdXNlIHRoZSBTMiBkYXRhIGJlY2F1c2UgaXQgaXMgbW9yZSBwcmVjaXNlICgxMCBtIHZzIDMwIG0pLg0KDQpgYGB7cn0NCmRhdGFfUlNfUzJfSUQgPC0gZGF0YV9SU19TMl9JRCAlPiUNCiAgcmVuYW1lKE5EVklfUzIgPSBORFZJLCBORE1JX1MyID0gTkRNSSkgJT4lDQogIHNlbGVjdCgtc291cmNlKQ0KZGF0YV9SU19MYW5kc2F0X0lEIDwtIGRhdGFfUlNfTGFuZHNhdF9JRCAlPiUNCiAgcmVuYW1lKE5EVklfTGFuZHNhdCA9IE5EVkksIE5ETUlfTGFuZHNhdCA9IE5ETUkpICU+JQ0KICBzZWxlY3QoLXNvdXJjZSkNCmBgYA0KDQpKb2luIFMyLCBTMl9waGVuIGFuZCBMYW5kc2F0IGRhdGE6DQoNCmBgYHtyfQ0KZGF0YV9SUyA8LSBkYXRhX1JTX1MyX0lEICU+JSANCiAgZnVsbF9qb2luKGRhdGFfUlNfUzJfcGhlbl9JRCkgJT4lDQogIGZ1bGxfam9pbihkYXRhX1JTX0xhbmRzYXRfSUQpDQpgYGANCg0KTnVtYmVyIG9mIG9ic2VydmF0aW9ucyB3aXRoIE5EVkkgZGF0YSBmcm9tIGJvdGggUzIgYW5kIExhbmRzYXQ6DQoNCmBgYHtyfQ0KbnJvdyhkYXRhX1JTICU+JSBmaWx0ZXIoIWlzLm5hKE5EVklfUzIpICYgIWlzLm5hKE5EVklfTGFuZHNhdCkpKQ0KYGBgDQoNClNlbmQgcG9pbnRzIGluIC5jc3YgdG8gQmVhLg0KDQpgYGB7cn0NCndyaXRlLmNzdihkYXRhX1JTICU+JSBmaWx0ZXIoIWlzLm5hKE5EVklfUzIpICYgIWlzLm5hKE5EVklfTGFuZHNhdCkpLA0KICAgICAgICAgIGZpbGUgPSBoZXJlKCJkYXRhIiwgImNsZWFuIiwgInBvaW50c19ORFZJX1MyX0xhbmRzYXQuY3N2IikpDQpgYGANCg0KRGlmZmVyZW5jZSBiZXR3ZWVuIE5EVkkgdmFsdWVzIGZyb20gUzIgYW5kIExhbmRzYXQ6DQoNCmBgYHtyfQ0KZGF0YV9SUyAlPiUgZmlsdGVyKCFpcy5uYShORFZJX1MyKSAmICFpcy5uYShORFZJX0xhbmRzYXQpKSAlPiUNCiAgbXV0YXRlKGRpZmZfTkRWSSA9IE5EVklfUzIgLSBORFZJX0xhbmRzYXQpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBkaWZmX05EVkkpKSArIGdlb21faGlzdG9ncmFtKGNvbG9yID0gImJsYWNrIiwgZmlsbCA9ICJ3aGl0ZSIpDQpkYXRhX1JTICU+JSBmaWx0ZXIoIWlzLm5hKE5ETUlfUzIpICYgIWlzLm5hKE5ETUlfTGFuZHNhdCkpICU+JQ0KICBtdXRhdGUoZGlmZl9ORE1JID0gTkRNSV9TMiAtIE5ETUlfTGFuZHNhdCkgJT4lDQogIGdncGxvdChhZXMoeCA9IGRpZmZfTkRNSSkpICsgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIikNCmBgYA0KDQpUaGVyZSBpcyBhIGxhcmdlIGRpZmZlcmVuY2UgYmV0d2VlbiBORFZJIHZhbHVlcyBmcm9tIFMyIGFuZCBMYW5kc2F0LiBTbyBmYXIsIHVzZSB0aGUgUzIgZGF0YSwgYnV0IGNoZWNrIHdpdGggQmVhLg0KDQpXaGVuIE5EVkkgYW5kIE5ETUkgdmFsdWVzIGFyZSBhdmFpbGFibGUgZnJvbSBib3RoIHNhdGVsbGl0ZXMsIHVzZSBTMjoNCg0KYGBge3J9DQpkYXRhX1JTIDwtIGRhdGFfUlMgJT4lDQogIG11dGF0ZShORFZJID0NCiAgICAgICAgICAgY2FzZV93aGVuKA0KICAgICAgICAgICAgIGlzLm5hKE5EVklfUzIpICYgaXMubmEoTkRWSV9MYW5kc2F0KSB+IE5BX3JlYWxfLA0KICAgICAgICAgICAgIGlzLm5hKE5EVklfTGFuZHNhdCkgfiBORFZJX1MyLA0KICAgICAgICAgICAgIGlzLm5hKE5EVklfUzIpIH4gTkRWSV9MYW5kc2F0LA0KICAgICAgICAgICAgIFRSVUUgfiBORFZJX1MyKSwNCiAgICAgICAgIE5ETUkgPSANCiAgICAgICAgICAgY2FzZV93aGVuKA0KICAgICAgICAgICAgIGlzLm5hKE5ETUlfUzIpICYgaXMubmEoTkRNSV9MYW5kc2F0KSB+IE5BX3JlYWxfLA0KICAgICAgICAgICAgIGlzLm5hKE5ETUlfTGFuZHNhdCkgfiBORE1JX1MyLA0KICAgICAgICAgICAgIGlzLm5hKE5ETUlfUzIpIH4gTkRNSV9MYW5kc2F0LA0KICAgICAgICAgICAgIFRSVUUgfiBORE1JX1MyKSwNCiAgICAgICAgICkNCmBgYA0KDQpgYGB7cn0NCmRiX3Jlc3Vydl9SUyA8LSBkYl9yZXN1cnYgJT4lDQogIGxlZnRfam9pbihkYXRhX1JTICU+JSBzZWxlY3QoLW9ic191bmlxdWVfaWQpKSAlPiUNCiAgbGVmdF9qb2luKGRhdGFfUlNfQ0hfSUQgJT4lIHNlbGVjdCgtb2JzX3VuaXF1ZV9pZCkpICU+JQ0KICBtdXRhdGUoUzJfZGF0YSA9ICFpcy5uYShORFZJX1MyKSAmICFpcy5uYShORE1JX1MyKSwgDQogICAgICAgICBMYW5kc2F0X2RhdGEgPSAhaXMubmEoTkRWSV9MYW5kc2F0KSAmICFpcy5uYShORE1JX0xhbmRzYXQpLA0KICAgICAgICAgQ0hfZGF0YSA9ICFpcy5uYShjYW5vcHlfaGVpZ2h0KSkNCmBgYA0KDQpgYGB7cn0NCmRiX3Jlc3Vydl9SUyAlPiUgY291bnQoUzJfZGF0YSkNCmRiX3Jlc3Vydl9SUyAlPiUgY291bnQoTGFuZHNhdF9kYXRhKQ0KZGJfcmVzdXJ2X1JTICU+JSBjb3VudChDSF9kYXRhKQ0KYGBgDQoNCiMgU2F2ZSB0byBjbGVhbiBkYXRhDQoNClNhdmUgY2xlYW4gZmlsZSBmb3IgYW5hbHlzZXMgKHRvIGJlIHVwZGF0ZWQgY29udGludW91c2x5IGR1ZSB0byB1cGRhdGVzIGluIFJlU3VydmV5IGRhdGFiYXNlIGFuZCB1cGRhdGVzIG9uIFJTIGRhdGEpLg0KDQpgYGB7cn0NCndyaXRlX3RzdihkYl9yZXN1cnZfUlMsaGVyZSgiZGF0YSIsICJjbGVhbiIsImRiX3Jlc3Vydl9SU18yMDI1MDMyNy5jc3YiKSkNCmBgYA0KDQojIFNlc3Npb24gaW5mbw0KDQpgYGB7cn0NCnNlc3Npb25JbmZvKCkNCmBgYA0K